local Archy = LibStub("AceAddon-3.0"):GetAddon("Archy")
local Artifact = Archy:GetModule("Artifact", true) or Archy:NewModule("Artifact", "AceEvent-3.0", "AceTimer-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Archy")

local updateCounter = 0
local db

--local tooltip

StaticPopupDialogs["ARCHY_CONFIRM_SOLVE"] = {
	text = L["Your Archaeology skill is at %d of %d.  Are you sure you would like to solve this artifact before visiting a trainer?"],
	button1 = "Yes",
	button2 = "No",
	OnAccept = function()
		if Artifact.confirm then
			Artifact:SolveArtifact(Artifact.confirm.race, Artifact.confirm.useStones)
			Artifact.confirm = nil
		end
	end,
	OnCancel = function()
		Artifact.confirm = nil
	end,
	timeout = 0,
	sound = "levelup2",
	whileDead = false,
	hideOnEscape = true,
}

function Artifact:SolveArtifact(race, useStones)
	Archy.archData:SolveArtifact(race, useStones)
end

function Artifact:SolveAnyArtifact(useStones)
	if GetNumArchaeologyRaces() == 0 then return end
	local foundArtifactToSolve = false
	for race=1,GetNumArchaeologyRaces() do
		if not self:RaceBlacklisted(race) then
			if Archy.archData:CanSolveArtifact(race, useStones) then
				self:SolveArtifact(race, useStones)
				foundArtifactToSolve = true
				break
			end
		end
	end
	if not foundArtifactToSolve then
		Archy:Print(L["No artifacts were solvable"])
	end
end

local function getCoords(column, row)
	local xstart = (column * 56) / 512
	local ystart = (row * 42) / 512
	local xend = ((column + 1) * 56) / 512
	local yend = ((row + 1) * 42) / 512
	return xstart, xend, ystart, yend
end

local texcoords = setmetatable({}, {__index = function(t, k)
	local col,row = k:match("(%d+):(%d+)")
	col,row = tonumber(col), tonumber(row)
	local obj = {getCoords(col, row)}
	rawset(t, k, obj)
	return obj
end})

function Artifact:OnInitialize()
	db = Archy.db.profile
	self.frame = self:CreateListFrame()
end

function Artifact:ShowHideList()
	if db.general.show and db.artifacts.show and self.visible then
		self.frame:Show()
	else
		self.frame:Hide()
	end
end

local eventsRegistered = false
function Artifact:OnEnable()
	db = Archy.db.profile
	self:UpdateColors()
	self.visible = true
	self:RegisterArchaeologyEvents()
end

function Artifact:RegisterArchaeologyEvents()
	Archy.archData.RegisterCallback(self, "ArchDataTablesLoaded", "OnArchaeologyDataLoaded")
	Archy.archData.RegisterCallback(self, "ReceivedFragments", "OnReceiveFragments")
	Archy.archData.RegisterCallback(self, "ReceivedKeystone", "OnReceiveKeystone")
	Archy.archData.RegisterCallback(self, "ArtifactCompleted", "OnArtifactComplete")
	Archy.archData.RegisterCallback(self, "ArtifactsUpdated", "OnArtifactsUpdated")
	Archy.archData.RegisterCallback(self, "RaceUpdated", "OnRaceUpdated")
	Archy.archData.RegisterCallback(self, "BagUpdated", "OnBagUpdate")
	Archy.archData.RegisterCallback(self, "ArchSkillUpdated", "OnSkillChange")
	Archy.archData.RegisterCallback(self, "MapChanged", "OnMapChanged")
	
--	Archy.archData.RegisterCallback(self, "ArtifactHistoryReady", "OnHistoryReady")
--	self:RegisterEvent("PLAYER_ENTERING_WORLD", "OnArchaeologyDataLoaded")
--	self:RegisterEvent("BAG_UPDATE", "OnBagUpdate")
--	self:RegisterEvent("SKILL_LINES_CHANGED", "OnSkillChange")

	self:RegisterMessage("ArchyConfigChanged", "OnConfigChanged")
	self:RegisterMessage("ArchyColorChanged", "OnColorChanged")
	self:RegisterMessage("ArchyStealthMode", "OnStealthMode")
	self:RegisterMessage("ArchyPositionReset", "OnResetPosition")
--	Artifact:RegisterEvent("WORLD_MAP_UPDATE", "OnArchaeologyDataLoaded")
	eventsRegistered = true
end

function Artifact:UnregisterArchaeologyEvents()
	Archy.archData.UnregisterCallback(self, "ArchDataTablesLoaded")
	Archy.archData.UnregisterCallback(self, "ReceivedFragments")
	Archy.archData.UnregisterCallback(self, "ReceivedKeystone")
	Archy.archData.UnregisterCallback(self, "ArtifactCompleted")
	Archy.archData.UnregisterCallback(self, "ArtifactsUpdated")
	Archy.archData.UnregisterCallback(self, "RaceUpdated")
	Archy.archData.UnregisterCallback(self, "BagUpdated")
	Archy.archData.UnregisterCallback(self, "ArchSkillUpdated")
	Archy.archData.UnregisterCallback(self, "MapChanged")
--	Archy.archData.UnregisterCallback(self, "ArtifactHistoryReady")
--	self:UnregisterEvent("PLAYER_ENTERING_WORLD")
--	self:UnregisterEvent("BAG_UPDATE")
	self:UnregisterMessage("ArchyConfigChanged")
	self:UnregisterMessage("ArchyColorChanged")
	self:UnregisterMessage("ArchyStealthMode")
	self:UnregisterMessage("ArchyPositionReset")
--	Artifact:UnregisterEvent("WORLD_MAP_UPDATE")
	eventsRegistered = false
end

function Artifact:OnResetPosition()
	db = Archy.db.profile
	self.frame:ClearAllPoints()
	self.frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", db.artifacts.location.x, db.artifacts.location.y)
end

function Artifact:OnStealthMode()
	self.visible = not self.visible
	self:ShowHideList()
end

function Artifact:OnColorChanged()
	self:UpdateColors()
end

function Artifact:OnDisable()
	self:UnregisterArchaeologyEvents()
end

function Artifact:OnMapChanged(event, count)
	--self:UpdateListFrame(true)
	self:ShowHideList()
end

local lastRace
local refreshLastRaceOnBagUpdate
function Artifact:OnBagUpdate(event, race)
	self:UpdateRaceFrame(race.id, false)
--	if refreshLastRaceOnBagUpdate and lastRace then
--		self:UpdateRaceFrame(lastRace, true)
--		refreshLastRaceOnBagUpdate = false
--	end
end

function Artifact:OnSkillChange(event, rank, maxRank)
	local header = L["Artifacts"]
	if db.general.showRank then
		header = header .. " - " .. Archy:RankDisplay()
	end
	self.frame.header.text:SetText(header)
end

function Artifact:OnConfigChanged()
	db = Archy.db.profile
	self:SetScale()
	self:SetAlpha()
	self:UpdateListFrame()
	self:ShowHideList()
	self:OnSkillChange()
	self:UpdateColors()
end

function Artifact:OnArchaeologyDataLoaded()
	updateCounter = updateCounter + 1
	self:UpdateListFrame((updateCounter == 1))
	self:ShowHideList()
end

function Artifact:OnHistoryReady()
	self:UpdateListFrame(true)
end

function Artifact:OnArtifactsUpdated()
	self:UpdateListFrame(true)
end

function Artifact:OnRaceUpdated(event, race)
	self:UpdateRaceFrame(race.id, true)
end

function Artifact:UpdateRaceFrame(raceID, force)
	if raceID == nil then return false end
	local frame = self.frame["race" .. raceID]
	if not self:RaceBlacklisted(raceID) and (not db.artifacts.filter or self:RaceOnContinent(raceID)) then
		-- Show the race
		local artifact, race = Archy.archData:GetCurrentArtifactInfo(raceID, force)
		if artifact then
			frame.raceID = race.id
			frame.raceName = race.name
			local fragments = artifact.fragments
			if artifact.fragments >= artifact.totalFragments then
				fragments = "|cFF00FF00" .. fragments
			else
				local fragmentAdjust = Archy.archData:ComputeSocketAdjustment(artifact.sockets, artifact.keystonesAvailable)
				if fragments + fragmentAdjust >= artifact.totalFragments then
					fragments = "|cFFFFFF00" .. fragments
				end
			end
			
			frame.progress:SetText(fragments .. "/" .. artifact.totalFragments)
			frame.sockets.sockets = artifact.sockets
			frame.sockets.keystones = artifact.keystonesAvailable
			frame.sockets.keystoneName = race.keystone.name
			
			if artifact.sockets > 0 or artifact.keystonesAvailable > 0 then
				frame.sockets.text:SetText(artifact.keystonesAvailable .. "/" .. artifact.sockets)
				frame.sockets:Show()
			else
				frame.sockets:Hide()
			end
			
			if race.texture and race.texture ~= "" then
				frame.solveButton.icon:SetTexture(race.texture)
				frame.solveButton.icon:SetTexture(race.texture)
			end
			
			local name = artifact.name
			if name then
				self:AnnounceAndPingIfReady(artifact, race)
				frame.artifactButton.rarity = (artifact.rarity ~= 0)
				frame.artifactButton.completionCount = artifact.completionCount or 0
--				if artifact.rarity ~= 0 and artifact.name then
--					name = Archy.rareItemColorCode .. name .. "|r"
--				elseif artifact.completionCount > 0 then
--					name = GRAY_FONT_COLOR_CODE .. name .. "|r"
--				else
--					name = name .. "|r"
--				end
			end
			frame.artifactButton.artifactName:SetText(name)
--			frame.artifactButton:SetWidth(frame.artifactButton.artifactName:GetStringWidth())
--			frame.artifactButton:SetHeight(frame.artifactButton.artifactName:GetStringHeight())
--			frame.progress:SetNonSpaceWrap(false)
--			frame.progress:SetWidth(frame.progress:GetStringWidth()+20)
--			frame.sockets:SetWidth(frame.sockets.text:GetStringWidth())
			
			
--			frame:SetHeight(22)
			frame:Show()
			self:UpdateColors()
			return true
		end
	end
	-- Do not show the race as it has been filtered
	frame:Hide()
	frame:SetHeight(1)
	return false
end

function Artifact:Resize()
	local height = 20
	local width = 1
	local maxFragWidth = 1
	local maxSocketWidth = 1
	local maxNameWidth = 1
	for i = 1, 12 do
		local cf = self.frame["race" .. i]
		if cf:IsVisible() then
			height = height + 22
		else
			height = height + 1
		end
		if maxFragWidth < cf.progress:GetStringWidth() + 20 then 
			maxFragWidth = cf.progress:GetStringWidth() + 20
		end
		if maxSocketWidth < cf.sockets.text:GetStringWidth() + 20 then 
			maxSocketWidth = cf.sockets.text:GetStringWidth() + 20
		end
		if maxNameWidth < cf.artifactButton.artifactName:GetStringWidth() + 20 then
			maxNameWidth = cf.artifactButton.artifactName:GetStringWidth() + 20
		end
	end
	for i = 1,12 do
		local cf = self.frame["race" .. i]
		cf.progress:SetWidth(maxFragWidth)
		cf.sockets.text:SetWidth(maxSocketWidth)
		cf.sockets:SetWidth(maxSocketWidth)
		cf.artifactButton.artifactName:SetWidth(maxNameWidth)
		cf.artifactButton:SetWidth(maxNameWidth)
	end
	self.frame:SetWidth(maxFragWidth + maxSocketWidth + maxNameWidth + 44)
--	self.frame:SetHeight(height)
end

function Artifact:UpdateListFrame(force)
	if GetNumArchaeologyRaces() == 0 then return end
	local racesVisible = 0
	for raceID = 1, GetNumArchaeologyRaces() do
		if self:UpdateRaceFrame(raceID, force) then racesVisible = racesVisible + 1 end
	end
	if racesVisible == 0 then self.frame:Hide() end
	self:UpdateColors()
end

function Artifact:SetScale()
	self.frame:SetScale(db.artifacts.scale)
end

function Artifact:SetAlpha()
	self.frame:SetAlpha(db.artifacts.alpha)
end

local pingList = {}
function Artifact:AnnounceAndPingIfReady(artifact, race)
	if pingList[race.id] then return end
	if pingList[race.id] == nil then
		pingList[race.id] = false
	end
	
	if db.artifacts.announce or db.artifacts.ping then

		if artifact.fragments >= artifact.totalFragments then
			pingList[race.id] = true
			if db.artifacts.announce then
				self:Announce(race.name, artifact.name, artifact.fragments, artifact.totalFragments)
			end
			if db.artifacts.ping then
				self:Ping()
			end
		end

		if pingList[race.id] then return end
		if db.artifacts.keystoneAnnounce or db.artifacts.keystonePing then
			local fragmentAdjust = Archy.archData:ComputeSocketAdjustment(artifact.sockets, artifact.keystonesAvailable)
			if artifact.fragments + fragmentAdjust >= artifact.totalFragments then
				pingList[race.id] = true
				if db.artifacts.announce then
					self:Announce(race.name, artifact.name, artifact.fragments + fragmentAdjust, artifact.totalFragments)
				end
				if db.artifacts.ping then
					self:Ping()
				end
			end
		end
	end
end

function Artifact:Announce(raceName, artifactName, fragments, totalFragments)
	if db.general.show then
		Archy:Print(string.format(L["You can solve %s Artifact - %s (Fragments: %d of %d)"], raceName, artifactName, min(fragments), totalFragments));
	end
end

function Artifact:Ping()
	if db.general.show then
		PlaySoundFile("Interface\\AddOns\\Archy\\Media\\dingding.mp3");
	end
end

function Artifact:RaceOnContinent(race)
	if not race then return false end
	local races = Archy.archData:GetRaceIDsForContinent(GetCurrentMapContinent())
	if not races then return end
	return tContains(races, race)
end

function Artifact:RaceBlacklisted(race)
	if not race then return false end
	if not db.artifacts.blacklist then return false end
	return tContains(db.artifacts.blacklist, race)
end

function Artifact:OnReceiveFragments(event, race, amount)
	self:UpdateRaceFrame(race.id, true)
	lastRace = race.id
	self:ShowHideList()
end

function Artifact:OnReceiveKeystone(event, race, amount)
	self:UpdateRaceFrame(race.id, true)
	lastRace = race.id
--	refreshLastRaceOnBagUpdate = true
end

function Artifact:OnArtifactComplete(event, artifact, race)
	if pingList[race.id] then pingList[race.id] = nil end
	self:UpdateRaceFrame(race.id, true)
	if db.general.show and db.artifacts.announce then
		Archy:Print(string.format(L["You have solved %s Artifact - %s (Times completed: %d)"], race.name, artifact.name, artifact.completionCount));
	end
	lastRace = race.id
	refreshLastRaceOnBagUpdate = true
end

function Artifact:UpdateColors()
	self.frame.background:SetTexture(db.artifacts.backgroundColor.Red, db.artifacts.backgroundColor.Green, db.artifacts.backgroundColor.Blue, db.artifacts.backgroundColor.Alpha)
	self.frame.headerBackground:SetTexture(db.artifacts.headerBackgroundColor.Red, db.artifacts.headerBackgroundColor.Green, db.artifacts.headerBackgroundColor.Blue, db.artifacts.headerBackgroundColor.Alpha)

	
	local headerFont = Archy.lsm:Fetch("font", db.artifacts.headerMedia.font)
	local headerSize = db.artifacts.headerMedia.fontSize
	local headerFlags = db.artifacts.headerMedia.fontOutline
	self.frame.header.text:SetFont(headerFont, headerSize, headerFlags)
	self.frame.header.text:SetTextColor(db.artifacts.headerMedia.fontColor.Red, db.artifacts.headerMedia.fontColor.Green, db.artifacts.headerMedia.fontColor.Blue, db.artifacts.headerMedia.fontColor.Alpha)
	self.frame.header:SetHeight(db.artifacts.headerMedia.height)
	self.frame.header.text:SetHeight(db.artifacts.headerMedia.height)
	self.frame.headerBackground:SetHeight(db.artifacts.headerMedia.height)
	self.frame.header:ClearAllPoints()
	self.frame.header:SetPoint("TOPLEFT", self.frame, "TOPLEFT")
	self.frame.header:SetPoint("TOPRIGHT", self.frame, "TOPRIGHT")
	self.frame.header.text:ClearAllPoints()
	self.frame.header.text:SetPoint("TOPLEFT", self.frame.header, "TOPLEFT", 20, 0)

	local font = Archy.lsm:Fetch("font", db.artifacts.rowMedia.font)
	local size = db.artifacts.rowMedia.fontSize
	local flags = db.artifacts.rowMedia.fontOutline
	local color = db.artifacts.rowMedia.fontColor
	local keystoneColor = db.artifacts.rowMedia.keystoneFontColor
	local grayColor = db.artifacts.rowMedia.grayFontColor
	local rareColor = db.artifacts.rowMedia.rareFontColor
	local topPoint = self.frame.header
	local bgHeight = 0
	local iconSpacing = db.artifacts.rowMedia.height * -0.5 -- -0.342
	for i = 1, 12 do
		local cf = self.frame["race"..i]
		cf.progress:SetFont(font, size, flags)
		cf.progress:SetTextColor(color.Red, color.Green, color.Blue, color.Alpha)
		cf.artifactButton.artifactName:SetFont(font, size, flags)
		cf.sockets.text:SetFont(font, size, flags)
		cf.sockets.text:SetTextColor(keystoneColor.Red,keystoneColor.Green, keystoneColor.Blue, keystoneColor.Alpha)
		cf.solveButton:SetHeight(db.artifacts.rowMedia.height)
		cf.solveButton:SetWidth(db.artifacts.rowMedia.height)
		cf.solveButton.icon:SetHeight(db.artifacts.rowMedia.height*2)
		cf.solveButton.icon:SetWidth(db.artifacts.rowMedia.height*2)

		cf.solveButton:ClearAllPoints()
		cf.solveButton:SetPoint("LEFT", cf.sockets, "RIGHT", 0, 0)
		cf.artifactButton:ClearAllPoints()
		cf.artifactButton:SetPoint("LEFT", cf.solveButton, "RIGHT", 10, 0)

		if cf.artifactButton.rarity then
			cf.artifactButton.artifactName:SetTextColor(rareColor.Red, rareColor.Green, rareColor.Blue, rareColor.Alpha)
		elseif cf.artifactButton.completionCount and cf.artifactButton.completionCount > 0 then
			cf.artifactButton.artifactName:SetTextColor(grayColor.Red, grayColor.Green, grayColor.Blue, grayColor.Alpha)
		else
			cf.artifactButton.artifactName:SetTextColor(color.Red, color.Green, color.Blue, color.Alpha)
		end

		cf:ClearAllPoints()
		if cf:IsVisible() then
			cf:SetPoint("TOPLEFT", topPoint, "BOTTOMLEFT", 0, -3)
			cf:SetHeight(db.artifacts.rowMedia.height)
			bgHeight = bgHeight + db.artifacts.rowMedia.height + 3
			topPoint = cf
		else
			cf:SetPoint("TOPLEFT", self.frame.noRaceAnchor, "BOTTOMLEFT", 0, 0)
		end
	end
	self.frame.background:ClearAllPoints()
	self.frame.background:SetPoint("TOPLEFT", self.frame.header, "BOTTOMLEFT")
	self.frame.background:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMRIGHT")
	self.frame:SetHeight(self.frame.headerBackground:GetHeight() + bgHeight + 5)
--	self.frame.background:SetHeight(bgHeight)
	self:Resize()
end

function Artifact:CreateListFrame()
	local frame = CreateFrame("Frame", "Artifacts", UIParent, "ArchyArtifactListFrame")
	frame:ClearAllPoints()
	frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", db.artifacts.location.x, db.artifacts.location.y)
	frame:SetScale(db.artifacts.scale)
	frame:SetAlpha(db.artifacts.alpha)
	
	local hdrBg = frame.header:CreateTexture("ArchyArtifactHeaderBackground", "BACKGROUND")
	hdrBg:SetPoint("TOPLEFT", frame.header, "TOPLEFT", 0, 0)
	hdrBg:SetPoint("BOTTOMRIGHT", frame.header, "BOTTOMRIGHT", 0, 0)
	hdrBg:SetTexture(0,0,0,0)
	frame.headerBackground = hdrBg

	local bg = frame:CreateTexture("ArchyArtifactBackground", "BACKGROUND")
	bg:SetPoint("TOPLEFT", frame.header, "BOTTOMLEFT")
	bg:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT")
	bg:SetTexture(0,0,0,0)
	frame.background = bg
	
	
	
	frame:SetScript("OnShow", function(self) Artifact:UpdateListFrame() end)
	frame.header:SetScript("OnMouseDown", function(self, button)
		if not db.general.lock then
			if button == "LeftButton" and not self:GetParent().isMoving then
				self:GetParent():StartMoving()
				self:GetParent().isMoving = true
			end
		end
	end)
	frame.header:SetScript("OnMouseUp", function(self, button)
		if not db.general.lock then
			if button == "LeftButton" and self:GetParent().isMoving then
				self:GetParent():StopMovingOrSizing()
				self:GetParent().isMoving = false
				local point, relativeTo, relativePoint, x, y = self:GetParent():GetPoint()
				db.artifacts.location.x = x
				db.artifacts.location.y = y
			end
		end
	end)
	frame.header:SetScript("OnHide", function(self)
		if ( self:GetParent().isMoving ) then
			self:GetParent():StopMovingOrSizing()
			self:GetParent().isMoving = false
		end
	end)
	
	for i = 1, 12 do
		local cf = frame["race" .. i]
		cf:Hide()
		cf:SetHeight(1)
		cf.sockets:SetScript("OnEnter", function(self)
			GameTooltip:SetOwner(self, "ANCHOR_NONE")
			GameTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT")
			GameTooltip:ClearLines()
			local keystoneName = self.keystoneName or L["Key stone"]
			GameTooltip:AddLine(string.format(L["%d Key stone sockets available"], self.sockets), 1, 1, 0);
			GameTooltip:AddLine(string.format(L["%d %ss in your inventory"],self.keystones,keystoneName), 1, 1, 1);
			GameTooltip:Show();
		end)
		cf.sockets:SetScript("OnLeave", function(self) GameTooltip:Hide() end)
		
		cf.solveButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")
		cf.solveButton:SetScript("OnClick", function(self, button, down)
			local useStones = false
			if button == "RightButton" then useStones = true end
			local rank, maxRank = Archy.archData:GetArchaeologyRank()
			if rank and maxRank then
				local requiresConfirm = false
				if db.artifacts.confirmSolve and maxRank < Archy.maxArchaeologySkill and (rank + 25) >= maxRank then requiresConfirm = true end
				if requiresConfirm then
					if not Artifact.confirm then Artifact.confirm = {} end
					Artifact.confirm.race = self:GetParent().raceID
					Artifact.confirm.useStones = useStones
					StaticPopup_Show("ARCHY_CONFIRM_SOLVE", rank, maxRank)
				else
					Artifact:SolveArtifact(self:GetParent().raceID, useStones)
				end
			end
		end)
		cf.solveButton:SetScript("OnDisable", function(self)
			SetDesaturation(self:GetNormalTexture(), true);
			self:GetNormalTexture():SetAlpha(0.6);
		end)
		cf.solveButton:SetScript("OnEnable", function(self)
			SetDesaturation(self:GetNormalTexture(), false);
			self:GetNormalTexture():SetAlpha(1.0);
		end)
		cf.solveButton:SetScript("OnEnter", function(self)
			GameTooltip:SetOwner(self, "ANCHOR_NONE")
			GameTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT")
			GameTooltip:ClearLines()
			GameTooltip:AddLine(self:GetParent().artifactButton.artifactName:GetText(), 1, 1, 0);
			GameTooltip:AddLine(L["Race: "] .. self:GetParent().raceName, 1, 1, 1);
			GameTooltip:AddLine(L["Left-Click to solve without key stones"], 0, 1, 0)
			GameTooltip:AddLine(L["Right-Click to solve with key stones"], 0, 1, 0)
			GameTooltip:Show()	
		end)
		cf.solveButton:SetScript("OnLeave", function() GameTooltip:Hide() end)
		
		cf.artifactButton:SetScript("OnClick", function(self, button, down)
			if Archy:ShowArchaeology() then
				ArchaeologyFrame_ShowArtifact(self:GetParent().raceID);
			end
		end)
		cf.artifactButton:SetScript("OnEnter", function(self)
			GameTooltip:SetOwner(self, "ANCHOR_NONE");
			GameTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT");
			GameTooltip:ClearLines();
			GameTooltip:AddLine(self.artifactName:GetText(), 1, 1, 0);
			GameTooltip:AddLine(L["Race: "] .. self:GetParent().raceName, 1, 1, 1);
			GameTooltip:AddLine(L["Click to view this artifact"], 0, 1, 0);
			GameTooltip:Show();
		end)
		cf.artifactButton:SetScript("OnLeave", function(self) GameTooltip:Hide() end)
	end

	return frame
end